﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Concurrent;

namespace CSharpExperiments.Collections
{
	public class ConcurrentDictionary<K1, K2, V> : ConcurrentDictionary<Tuple<K1, K2>, V>
	{
		public V this[K1 key1, K2 key2]
		{
			get { return this[Tuple.Create(key1, key2)]; }
			set { this[Tuple.Create(key1, key2)] = value; }
		}

		public IEnumerable<KeyValuePair<Tuple<K1, K2>, V>> GetByKey1(K1 key1)
		{
			return this.Where(x => Object.Equals(x.Key.Item1, key1));
		}

		public IEnumerable<KeyValuePair<Tuple<K1, K2>, V>> GetByKey2(K2 key2)
		{
			return this.Where(x => Object.Equals(x.Key.Item2, key2));
		}

		public IEnumerable<KeyValuePair<Tuple<K1, K2>, V>> GetByKey1(Func<K1, bool> predicate)
		{
			return this.Where(x => predicate(x.Key.Item1));
		}

		public IEnumerable<KeyValuePair<Tuple<K1, K2>, V>> GetByKey2(Func<K2, bool> predicate)
		{
			return this.Where(x => predicate(x.Key.Item2));
		}

		public V GetOrAdd(K1 key1, K2 key2, V defaultValue)
		{
			return this.GetOrAdd(Tuple.Create(key1, key2), defaultValue);
		}

		public V GetOrAdd(K1 key1, K2 key2, Func<K1, K2, V> valueFactory)
		{
			return this.GetOrAdd(Tuple.Create(key1, key2), valueFactory.Tuplize());
		}
	}

	public class ConcurrentDictionary<K1, K2, K3, V> : ConcurrentDictionary<Tuple<K1, K2, K3>, V>
	{
		public V this[K1 key1, K2 key2, K3 key3]
		{
			get { return this[Tuple.Create(key1, key2, key3)]; }
			set { this[Tuple.Create(key1, key2, key3)] = value; }
		}

		public IEnumerable<KeyValuePair<Tuple<K1, K2, K3>, V>> GetByKey1(K1 key1)
		{
			return this.Where(x => Object.Equals(x.Key.Item1, key1));
		}

		public IEnumerable<KeyValuePair<Tuple<K1, K2, K3>, V>> GetByKey2(K2 key2)
		{
			return this.Where(x => Object.Equals(x.Key.Item2, key2));
		}

		public IEnumerable<KeyValuePair<Tuple<K1, K2, K3>, V>> GetByKey3(K3 key3)
		{
			return this.Where(x => Object.Equals(x.Key.Item3, key3));
		}

		public IEnumerable<KeyValuePair<Tuple<K1, K2, K3>, V>> GetByKey1(Func<K1, bool> predicate)
		{
			return this.Where(x => predicate(x.Key.Item1));
		}

		public IEnumerable<KeyValuePair<Tuple<K1, K2, K3>, V>> GetByKey2(Func<K2, bool> predicate)
		{
			return this.Where(x => predicate(x.Key.Item2));
		}

		public IEnumerable<KeyValuePair<Tuple<K1, K2, K3>, V>> GetByKey3(Func<K3, bool> predicate)
		{
			return this.Where(x => predicate(x.Key.Item3));
		}
	}

	public class ConcurrentDictionary<K1, K2, K3, K4, V> : ConcurrentDictionary<Tuple<K1, K2, K3, K4>, V>
	{
		public V this[K1 key1, K2 key2, K3 key3, K4 key4]
		{
			get { return this[Tuple.Create(key1, key2, key3, key4)]; }
			set { this[Tuple.Create(key1, key2, key3, key4)] = value; }
		}

		public IEnumerable<KeyValuePair<Tuple<K1, K2, K3, K4>, V>> GetByKey1(K1 key1)
		{
			return this.Where(x => Object.Equals(x.Key.Item1, key1));
		}

		public IEnumerable<KeyValuePair<Tuple<K1, K2, K3, K4>, V>> GetByKey2(K2 key2)
		{
			return this.Where(x => Object.Equals(x.Key.Item2, key2));
		}

		public IEnumerable<KeyValuePair<Tuple<K1, K2, K3, K4>, V>> GetByKey3(K3 key3)
		{
			return this.Where(x => Object.Equals(x.Key.Item3, key3));
		}

		public IEnumerable<KeyValuePair<Tuple<K1, K2, K3, K4>, V>> GetByKey4(K4 key4)
		{
			return this.Where(x => Object.Equals(x.Key.Item4, key4));
		}

		public IEnumerable<KeyValuePair<Tuple<K1, K2, K3, K4>, V>> GetByKey1(Func<K1, bool> predicate)
		{
			return this.Where(x => predicate(x.Key.Item1));
		}

		public IEnumerable<KeyValuePair<Tuple<K1, K2, K3, K4>, V>> GetByKey2(Func<K2, bool> predicate)
		{
			return this.Where(x => predicate(x.Key.Item2));
		}

		public IEnumerable<KeyValuePair<Tuple<K1, K2, K3, K4>, V>> GetByKey3(Func<K3, bool> predicate)
		{
			return this.Where(x => predicate(x.Key.Item3));
		}

		public IEnumerable<KeyValuePair<Tuple<K1, K2, K3, K4>, V>> GetByKey4(Func<K4, bool> predicate)
		{
			return this.Where(x => predicate(x.Key.Item4));
		}
	}
}
